/*
 * tcp_socketClient_tsk.c
 *
 *  Created on: Dec 10, 2020
 *      Author: zchaojian
 */

#include "tcp_socketClient_tsk.h"
#include "config_app.h"
#include "download_tcp_server.h"
#include "esp_log.h"
#include "eth_connect.h"
#include "freertos/timers.h"
#include "lwip/sockets.h"
#include "tcpSocket_tsk.h"
#include "tcp_socketServer_tsk.h"
#include "udp_brdcast.h"
#include "wifi_connect.h"

static uint8_t mTcpClientConnected = 0;
static int mClientSocket = 0;

static uint32_t mClientIP = 0;
static uint16_t mClientPort = 0;
static int mClientAddrFamily;

static const char* TAG = "TCP_SocketClient";

/* define tcp client send timer*/
TimerHandle_t TcpClientSendTimerHandle;

// void Start_Ping_ESP32(void);
/* define a timer callback function */
static void vTcpClientSendTimerCallback(TimerHandle_t xTimer)
{
    int uiSendDataFlag;
    char cHeart[8] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff };

    if (mTcpClientConnected > 0) {
        uiSendDataFlag = send(mClientSocket, cHeart, sizeof(cHeart), 0);
        if (uiSendDataFlag < 0) {
            vTcp_SocketClient_Close();
            mTcpClientConnected = 0;
            xTimerReset(TcpClientSendTimerHandle, 0);
            // esp_timer_delete(esp_timer_delete);
        }
    }
}

/*start a timer*/
static void vStartTcpClientTimer()
{
    BaseType_t ret = 0;

    if ((TcpClientSendTimerHandle != NULL))
        ret = xTimerStart(TcpClientSendTimerHandle, 0); /* 创建成功，开启定时器*/
    else
        ESP_LOGE(TAG, "TCP Client Timer Create failure !!! "); /* 定时器创建失败 */

    if (ret == pdPASS)
        ESP_LOGI(TAG, "TCP Client Timer Start OK."); /* 定时器启动成功*/
    else
        ESP_LOGE(TAG, "TCP Client Timer Start err."); /* 定时器启动失败*/
}

static void vTCP_SocketClient_Init(void)
{
    static struct sockaddr_in tDestAddr, local_addr;
    static struct sockaddr_in6 tDestAddr6 = { 0 };
    char ip[4] = { 0 };
    uint16_t hxPort = mPartitionTable.tEthernetConfig.EthernetPort + 1;
    if (mClientAddrFamily == AF_INET) {
        tDestAddr.sin_addr.s_addr = mClientIP;
        tDestAddr.sin_family = AF_INET;
        tDestAddr.sin_port = htons(mClientPort);
    } else if (mClientAddrFamily == AF_INET6) {
        inet6_aton(mClientIP, &tDestAddr6.sin6_addr);
        tDestAddr6.sin6_family = AF_INET6;
        tDestAddr6.sin6_port = htons(mClientPort);
        // dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
    }
    mClientSocket = socket(mClientAddrFamily, SOCK_STREAM, mClientAddrFamily == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP);
    if (mClientSocket < 0) {
        ESP_LOGE(TAG, "Ethernet socket client creat fail!");
        shutdown(mClientSocket, SHUT_RDWR);
        close(mClientSocket);
        return;
    }
    ESP_LOGI(TAG, "Ethernet socket client created!");

    // int iErr = bind(mClientSocket, (struct sockaddr*)&tDestAddr, sizeof(tDestAddr));
    // if (iErr != 0) {
    //     ESP_LOGE(TAG, "Ethernet socket server bind creat fail!");
    //     shutdown(mClientSocket, SHUT_RDWR);
    //     close(mClientSocket);
    //     return;
    // }

    // 配置本地地址和端口
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = INADDR_ANY; // 绑定到所有本地接口
    local_addr.sin_port = htons(hxPort);

    // 绑定套接字到本地地址和端口
    int iErr = bind(mClientSocket, (struct sockaddr*)&local_addr, sizeof(local_addr));
    if (iErr != 0) {
        ESP_LOGE(TAG, "Ethernet socket client bind fail!");
        shutdown(mClientSocket, SHUT_RDWR);
        close(mClientSocket);
        return;
    }
    ESP_LOGI(TAG, "Ethernet socket client bind created! Port:%d", hxPort);
    int err = connect(mClientSocket, mClientAddrFamily == AF_INET6 ? (struct sockaddr*)&tDestAddr6 : (struct sockaddr*)&tDestAddr, sizeof(struct sockaddr_in6));
    if (err != 0) {
        ESP_LOGE(TAG, "Ethernet socket client connect fail!");
        shutdown(mClientSocket, SHUT_RDWR);
        close(mClientSocket);
        return;
    }
    // 设置保活参数
    set_keepalive(mClientSocket, KEEP_IDLE, KEEP_INTERVAL, KEEP_PROBE_TIMES);
    ESP_LOGI(TAG, "Ethernet socket client connected! mClientSocket:%d", mClientSocket);
    ip[0] = (char)(mClientIP & 0xFF);
    ip[1] = (char)((mClientIP >> 8) & 0xFF);
    ip[2] = (char)((mClientIP >> 16) & 0xFF);
    ip[3] = (char)((mClientIP >> 24) & 0xFF);
    ESP_LOGI(TAG, "ETH Connect IP:%d.%d.%d.%d, Port: %d", ip[0], ip[1], ip[2], ip[3], mClientPort);
    mTcpClientConnected = 1;
    memset(tcp_info_buff[8].IP, 0, 32);
    sprintf(tcp_info_buff[8].IP, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
    tcp_info_buff[8].connect_fd = mClientSocket;
    tcp_info_buff[8].port = mClientPort;
    tcp_info_buff[8].role = REMOTE_SERVER;
    vStartTcpClientTimer();
    // vAddClientFdToAllSockets(mClientSocket);
}

static void vTcp_Client_Task(void* pvParameters)
{
    char cRxBuffer[CONFIG_SOCKET_FRAME_SIZE];
    uint8_t mConnectedLocal;
    uint8_t uUDPServerCreated;
    uint8_t ucOTATcpServerListened;
    ModbusRtuDataTPDF* mModbusRtuDataRec = NULL;
    mModbusRtuDataRec = pModbusRtuDataRec();
    while (1) {
        mConnectedLocal = Eth_Connected_Status() | Wifi_Connected_Status();
        uUDPServerCreated = uUdp_SocketServerCreated();
        if (mConnectedLocal & uUDPServerCreated) {
            if (!mTcpClientConnected) {
                vTCP_SocketClient_Init();
                // Start_Ping_ESP32();
            } else {
                while (1) {
                    int iLen = recv(mClientSocket, cRxBuffer, sizeof(cRxBuffer) - 1, 0);
                    // Error occurred during receiving
                    if (iLen < 0) {
                        ESP_LOGE(TAG, "Ethernet socket client data recv fail!");
                        break;
                    } else {
                        // Data received
                        cRxBuffer[iLen] = 0; // Null-terminate whatever we received and treat like a string
                        if (ANA_LOG) {
                            ESP_LOGW(TAG, "---------------new client data---------------Len: %d", iLen);
                            esp_log_buffer_hex(TAG, cRxBuffer, iLen);
                        }
                        // MODB_vAnalysis_TCP((uint8_t *)cRxBuffer, iLen, mClientModbusRtuDataRec);
                        // mClientModbusRtuDataRec->tTag = (void *)mClientSocket;
                        xSemaphoreTake(ModbusTCP_handle_sem, pdMS_TO_TICKS(5000));
                        MODB_vAnalysis_TCP((uint8_t*)cRxBuffer, iLen, mModbusRtuDataRec);
                        xSemaphoreGive(ModbusTCP_handle_sem);
                        mModbusRtuDataRec->tTag = (void*)mClientSocket;
                    }
                    vTaskDelay(2);
                }

                if (mClientSocket != -1) {
                    ESP_LOGE(TAG, "Ethernet socket client disconnected!");
                    memset(tcp_info_buff + 8, 0, sizeof(J_tcp_connect_info_t));
                    shutdown(mClientSocket, 0);
                    close(mClientSocket);
                    mTcpClientConnected = 0;
                }
            }
        }
        vTaskDelay(200);
    }
}

/*tcp socket  client task initialize*/
void vTcpClientTask_vInit(uint32_t uiSocketIP, uint16_t usSocketPort, int iAddrFamily)
{
    uint16_t usHeartTime;
    mClientIP = uiSocketIP;
    mClientPort = usSocketPort;
    mClientAddrFamily = iAddrFamily;
    usHeartTime = mPartitionTable.tServer1Config.usHeartTime > 0 ? mPartitionTable.tServer1Config.usHeartTime : 60;
    ESP_LOGI(TAG, "heartTime = %d", usHeartTime);

    xTaskCreate(vTcp_Client_Task, "socket client task", 4096, NULL, 4, NULL);

    TcpClientSendTimerHandle = xTimerCreate((const char*)"TcpClientSendTimer", /* 软件定时器名称 */
        (TickType_t)(usHeartTime * 1000 / portTICK_PERIOD_MS), /* 定时周期，单位为时钟节拍 */
        (UBaseType_t)pdTRUE, /* 定时器模式，是否为周期定时模式 */
        (void*)1, /* 定时器ID号 */
        (TimerCallbackFunction_t)vTcpClientSendTimerCallback); /*定时器回调函数 */
}

/*tcp socker client close*/
void vTcp_SocketClient_Close(void)
{
    if (mTcpClientConnected) {
        close(mClientSocket);
    }
}

/* Use function return tcp socket client connect status */
uint8_t uTcp_SocketClientConnected(void)
{
    return mTcpClientConnected;
}

/* remote server down, the local client need change status */
void vChangeSocketClientConnectValue(uint8_t ucConnectValue)
{
    mTcpClientConnected = ucConnectValue;
}

// esp_err_t pingResults(ping_target_id_t msgType, esp_ping_found * pf)
// {
//     printf("AvgTime:%.1fmS Sent:%d Rec:%d min(mS):%d max(mS):%d Resp(mS):%d Timeouts:%d Total Time:%d\n", (float)pf->total_time/pf->recv_count, pf->send_count, pf->recv_count,  pf->min_time, pf->max_time ,pf->resp_time, pf->timeout_count, pf->total_time);
//     return ESP_OK;
// }

// void Start_Ping_ESP32(void)
// {

//     uint32_t ip_pinG = ipaddr_addr("180.166.23.62");//百度IP地址
//     uint32_t ping_count = 2000;//ping的次数
//     uint32_t ping_timeout = 1000; //超时时间
//     uint32_t ping_delay = 5000; //ping 的间隔
//     ping_deinit();
//     esp_ping_set_target(PING_TARGET_IP_ADDRESS_COUNT, &ping_count, sizeof(uint32_t));
//     esp_ping_set_target(PING_TARGET_RCV_TIMEO, &ping_timeout, sizeof(uint32_t));
//     esp_ping_set_target(PING_TARGET_DELAY_TIME, &ping_delay, sizeof(uint32_t));
//     esp_ping_set_target(PING_TARGET_IP_ADDRESS, &ip_pinG, sizeof(uint32_t));
//     esp_ping_set_target(PING_TARGET_RES_FN, &pingResults, sizeof(pingResults));

//     res = ping_init();
//     if(res == 0){
//         printf("PING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
//     }else{
//         printf("error:%d\n",res);
//     }
// }
